﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Diagnostics;

namespace BubbleBlastSolver.Classes.BusinessLogic
{
    class Game
    {
        private UInt32 m_solutionCounter = 0;
        private uint m_totalClicks;
        private bool m_IsSolved = false;
        private Dictionary<UInt32, BubbleSession> m_sessionsDictionary = new Dictionary<UInt32, BubbleSession>();
        private int m_ClickCounter = 0;

        public Game()
        {
        }

        public void Solve(BubbleSession startSession, uint numberOfClickAttempts)
        {
            //startSession = this.CreateTestSession_3_31();

            this.m_totalClicks = numberOfClickAttempts;

            m_IsSolved = false;
            this.m_sessionsDictionary.Clear();
            
            this.SolveRecursively(startSession, this.m_totalClicks);

            Debug.WriteLine(String.Format("========== Solve finished! No. of clicks: {0} ==========", this.m_ClickCounter.ToString()));
        }

        public void Test()
        {
            BubbleSession session1 = this.CreateTestSession_1_35();
            BubbleSession session2 = session1.ClickAtPosition(0, 0);
            BubbleSession session3 = session2.ClickAtPosition(2, 2);
            BubbleSession session4 = session3.ClickAtPosition(4, 3);
        }

        private void SolveRecursively(BubbleSession currentSession, uint remainingClicks)
        {
            if (this.m_sessionsDictionary.Keys.Contains(currentSession.Index))
            {
                this.m_sessionsDictionary.Remove(currentSession.Index);
            }
            this.m_sessionsDictionary.Add(currentSession.Index, currentSession);

            if (this.m_IsSolved)
            {
                return;
            }

            if (remainingClicks > 0)
            {
                --remainingClicks;
            }
            else
            {
                return;
            }

            BubbleSession nextSession;

            while (true)
            {
                nextSession = currentSession.ClickAtCurrentPosition();
                ++this.m_ClickCounter;

                if (nextSession.IsEmpty)
                {
                    this.PrintSolution();
                    //this.m_IsSolved = true;
                    return;
                }

                if (remainingClicks > 0)
                {
                    this.SolveRecursively(nextSession, remainingClicks);
                }

                if (this.m_IsSolved)
                {
                    //return;
                }

                if (!currentSession.MoveToNextClickPosition())
                {
                    break;
                }
            }
        }

        private void PrintSolution()
        {
            ++this.m_solutionCounter;

            Debug.WriteLine("---------- Solution: " + this.m_solutionCounter.ToString() + "----------");

            foreach (BubbleSession session in this.m_sessionsDictionary.Values)
            {
                Debug.Write(session.DisplayName + " - ");
                Debug.Write(session.DisplayPositionName + "\n");
            }
        }

        private BubbleSession CreateTestSession_1_35()
        {
            BubbleSession testSession = new BubbleSession();

            testSession.Index = 1;

            // Row 0
            testSession.CreateBubbleIn(0, 0, 1);
            testSession.CreateBubbleIn(0, 3, 4);
            testSession.CreateBubbleIn(0, 4, 3);

            // Row 1
            testSession.CreateBubbleIn(1, 0, 4);
            testSession.CreateBubbleIn(1, 1, 1);
            testSession.CreateBubbleIn(1, 3, 1);
            testSession.CreateBubbleIn(1, 4, 3);

            // Row 2
            testSession.CreateBubbleIn(2, 0, 3);
            testSession.CreateBubbleIn(2, 1, 2);
            testSession.CreateBubbleIn(2, 2, 2);
            testSession.CreateBubbleIn(2, 3, 4);

            // Row 3
            testSession.CreateBubbleIn(3, 0, 2);
            testSession.CreateBubbleIn(3, 1, 1);
            testSession.CreateBubbleIn(3, 3, 1);
            testSession.CreateBubbleIn(3, 4, 3);

            // Row 4
            testSession.CreateBubbleIn(4, 1, 3);
            testSession.CreateBubbleIn(4, 2, 2);
            testSession.CreateBubbleIn(4, 3, 1);
            testSession.CreateBubbleIn(4, 4, 1);

            // Row 5
            testSession.CreateBubbleIn(5, 0, 1);
            testSession.CreateBubbleIn(5, 1, 4);
            testSession.CreateBubbleIn(5, 3, 4);
            testSession.CreateBubbleIn(5, 4, 4);

            testSession.Initialize();

            return testSession;
        }

        private BubbleSession CreateTestSession_3_29()
        {
            BubbleSession testSession = new BubbleSession();

            testSession.Index = 1;

            // Row 0
            testSession.CreateBubbleIn(0, 2, 1);
            testSession.CreateBubbleIn(0, 3, 1);
            testSession.CreateBubbleIn(0, 4, 3);

            // Row 1
            testSession.CreateBubbleIn(1, 0, 4);
            testSession.CreateBubbleIn(1, 1, 2);
            testSession.CreateBubbleIn(1, 2, 3);
            testSession.CreateBubbleIn(1, 3, 1);
            testSession.CreateBubbleIn(1, 4, 1);

            // Row 2
            testSession.CreateBubbleIn(2, 0, 1);
            testSession.CreateBubbleIn(2, 2, 2);
            testSession.CreateBubbleIn(2, 3, 3);
            testSession.CreateBubbleIn(2, 4, 3);

            // Row 3
            testSession.CreateBubbleIn(3, 0, 1);
            testSession.CreateBubbleIn(3, 1, 1);
            testSession.CreateBubbleIn(3, 2, 1);
            testSession.CreateBubbleIn(3, 3, 1);
            testSession.CreateBubbleIn(3, 4, 3);

            // Row 4
            testSession.CreateBubbleIn(4, 1, 2);
            testSession.CreateBubbleIn(4, 2, 4);
            testSession.CreateBubbleIn(4, 3, 3);
            testSession.CreateBubbleIn(4, 4, 1);

            // Row 5
            testSession.CreateBubbleIn(5, 1, 1);
            testSession.CreateBubbleIn(5, 2, 2);
            testSession.CreateBubbleIn(5, 3, 3);
            testSession.CreateBubbleIn(5, 4, 1);

            testSession.Initialize();

            return testSession;
        }

        private BubbleSession CreateTestSession_3_31()
        {
            BubbleSession testSession = new BubbleSession();

            testSession.Index = 1;

            // Row 0
            testSession.CreateBubbleIn(0, 1, 2);
            testSession.CreateBubbleIn(0, 2, 2);
            testSession.CreateBubbleIn(0, 3, 2);
            testSession.CreateBubbleIn(0, 4, 4);

            // Row 1
            testSession.CreateBubbleIn(1, 0, 1);
            testSession.CreateBubbleIn(1, 1, 4);
            testSession.CreateBubbleIn(1, 2, 1);
            testSession.CreateBubbleIn(1, 3, 3);
            testSession.CreateBubbleIn(1, 4, 2);

            // Row 2
            testSession.CreateBubbleIn(2, 0, 2);
            testSession.CreateBubbleIn(2, 1, 1);
            testSession.CreateBubbleIn(2, 2, 4);
            testSession.CreateBubbleIn(2, 3, 3);
            testSession.CreateBubbleIn(2, 4, 4);

            // Row 3
            testSession.CreateBubbleIn(3, 0, 3);
            testSession.CreateBubbleIn(3, 1, 1);
            testSession.CreateBubbleIn(3, 2, 1);
            testSession.CreateBubbleIn(3, 3, 3);
            testSession.CreateBubbleIn(3, 4, 1);

            // Row 4
            testSession.CreateBubbleIn(4, 0, 3);
            testSession.CreateBubbleIn(4, 2, 3);
            testSession.CreateBubbleIn(4, 3, 1);
            testSession.CreateBubbleIn(4, 4, 1);

            // Row 5
            testSession.CreateBubbleIn(5, 0, 2);
            testSession.CreateBubbleIn(5, 1, 3);
            testSession.CreateBubbleIn(5, 2, 3);
            testSession.CreateBubbleIn(5, 3, 2);
            testSession.CreateBubbleIn(5, 4, 2);

            testSession.Initialize();

            return testSession;
        }

    }
}
